/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "nfc_osi_api.h"
#include "nfc_log_api.h"
#include "nfc_secure_def.h"

/**
 * @file osi_memory.c
 * @brief 安全的内存操作API实现
*/

/**
 * @brief 安全的内存复制函数
 *
 * @param[out] dest   指向将要复制的目标内存的指针
 * @param[in]  destsz 复制目标内存的大小，单位：字节
 * @param[in]  src    指向复制目标原始内存的指针
 * @param[in]  count  需要复制内容的大小，单位：字节
 *
 * @return 成功返回true，其他情况返回false
*/
bool osi_memcpy(void *dest, size_t destsz, const void *src, size_t count)
{
    if (unlikely(count == 0)) {
        return true;
    }

    OSI_CHK_PARAM_INVALID(dest == NULL, return false);
    OSI_CHK_PARAM_INVALID(src == NULL, return false);
    OSI_CHK_PARAM_INVALID(destsz == 0, return false);
    OSI_CHK_PARAM_INVALID(count > destsz, return false);
    return memcpy_s(dest, destsz, src, count) == EOK;
}

/**
 * @brief 安全的内存设置函数
 *
 * @param[out] dest   指向将要被设置的目标内存的指针
 * @param[in]  destsz 将要被写入的目标内存大小，单位：字节
 * @param[in]  value  被写入的值
 * @param[in]  count  将要被写入的大小，单位：字节
 *
 * @return 成功返回true，其他情况返回false
*/
bool osi_memset(void *dest, size_t destsz, int value, size_t count)
{
    if (unlikely(count == 0)) {
        return true;
    }

    OSI_CHK_PARAM_INVALID(dest == NULL, return false);
    OSI_CHK_PARAM_INVALID(destsz == 0, return false);
    OSI_CHK_PARAM_INVALID(count > destsz, return false);
    return memset_s(dest, destsz, value, count) == EOK;
}

/**
 * @brief 安全的字符串复制函数
 *
 * @param[out] dest   指向将要复制的目标内存的指针
 * @param[in]  destsz 复制目标内存的大小，单位：字节
 * @param[in]  src    指向复制目标原始内存的指针
 * @param[in]  count  需要复制内容的大小，单位：字节
 *
 * @return 成功返回true，其他情况返回false
*/
bool osi_strncpy(char *dest, size_t destsz, const char *src, const size_t count)
{
    if (unlikely(count == 0)) {
        return true;
    }

    OSI_CHK_PARAM_INVALID(dest == NULL, return false);
    OSI_CHK_PARAM_INVALID(src == NULL, return false);
    OSI_CHK_PARAM_INVALID(destsz == 0, return false);
    OSI_CHK_PARAM_INVALID(count > destsz, return false);
    return strncpy_s(dest, destsz, src, count) == EOK;
}

/**
 * @brief 安全的格式化输出字符串函数
 *
 * @param[out] str   目标字符串，用于存储格式化后的字符串的字符数组的指针
 * @param[in]  strsz 字符数组的大小，单位：字节
 * @param[out] count 输出到str缓冲区中的字符数，不包括字符串结尾的空字符'\0'，单位：字节
 * @param[in]  fmt   格式化字符串
 * @param[in]  args  可变参数，可变数量的参数根据fmt中的格式化指令进行格式化
 *
 * @return 成功返回true，其他情况返回false
*/
bool osi_snprintf(char *str, size_t strsz, int *count, const char *fmt, ...)
{
    OSI_CHK_PARAM_INVALID(str == NULL, return false);
    OSI_CHK_PARAM_INVALID(strsz == 0, return false);
    OSI_CHK_PARAM_INVALID(count == NULL, return false);
    OSI_CHK_PARAM_INVALID(fmt == NULL, return false);
    va_list args;
    va_start(args, fmt);
    *count = vsnprintf_s(str, strsz, strsz, fmt, args);
    va_end(args);

    if (*count < 0) {
        NFCLOG_E("%s failed, error = %d", __func__, *count);
        return false;
    }

    OSI_CHK_PARAM_INVALID(*count > (strsz - 1), return false);
    return true;
}

/**
 * @brief 安全的字符串连接函数
 *
 * @param dest      目标缓冲区
 * @param dest_size 目标缓冲区的总大小
 * @param src       源字符串
 * @param count     要复制的最大字符数
 * @return          true 成功，false 失败
 */
bool osi_strncat(char *dest, size_t dest_size, const char *src, size_t count)
{
    OSI_CHK_PARAM_INVALID(!dest, return false);
    OSI_CHK_PARAM_INVALID(!src, return false);
    OSI_CHK_PARAM_INVALID(dest_size == 0, return false);

    size_t dest_len = strnlen(dest, dest_size);
    OSI_CHK_PARAM_INVALID(dest_len >= dest_size, return false);
    size_t remaining = dest_size - dest_len - 1;
    size_t copy_len = strnlen(src, count);
    if (copy_len > remaining) {
        copy_len = remaining;
    }

    osi_memcpy(dest + dest_len, remaining, src, copy_len);
    dest[dest_len + copy_len] = '\0';
    return true;
}
